//==================================================================
//  Copyright (C) 2006  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
//= Creation: Davide Pasca 2004
//=
//=
//=
//=
//==================================================================

#include "colconv.h"

//==================================================================
#define KYF		298L	// (298.082)
#define KRVF	408L	//.583)
#define KGUF	-100L	//.291)
#define KGVF	-208L	//.12)
#define KBUF	516L	//.411)

#define KYR	(float)( 65.738f/255.0f)
#define KYG	(float)(129.057f/255.0f)
#define KYB	(float)( 25.064f/255.0f)

#define KUR	(float)(-37.945f/255.0f)
#define KUG	(float)(-74.494f/255.0f)
#define KUB	(float)(112.439f/255.0f)

#define KVR	(float)(112.439f/255.0f)
#define KVG	(float)(-94.154f/255.0f)
#define KVB	(float)(-18.285f/255.0f)


#define KY	(float)(298.082f/255.0f)
#define KRU	0
#define KRV	(float)(408.583f/255.0f)

#define KGU	(float)(-100.291f/255.0f)
#define KGV	(float)(-208.12f/255.0f)

#define KBU	(float)(516.411f/255.0f)
#define KBV	0

//==================================================================
static void yuv411_bbb_to_bgr_flip_vert( u_char *rgbp, u_char *yp, signed char *up, signed char *vp, int w, int h, int uvrowlen )
{
int		i, j;
u_char	*rgbp2;
u_char	*yp2;
unsigned char	*up2, *vp2;
int		r, g, b;
int		y1, y2, ckr, ckg, ckb;
int		pckr, pckg, pckb;
int		yrowlen;
int		rgbpitch;

	rgbpitch = w * 3;
	rgbp += rgbpitch * h;
	yrowlen = w;
	for (i=h/2; i; --i)
	{
		rgbp -= rgbpitch*2;
		rgbp2 = rgbp;
		yp2 = yp;	yp += yrowlen*2;
		up2 = (u_char *)up;	up += uvrowlen;
		vp2 = (u_char *)vp;	vp += uvrowlen;
		pckr = pckg = pckb = 0;
		for (j=w/2; j; --j)
		{
		int	u, v;

			u = (int)*up2++ - 128;
			v = (int)*vp2++ - 128;
			ckr =            v * KRVF;
			ckg = u * KGUF + v * KGVF;
			ckb = u * KBUF;

			pckr = pckr + ckr >> 1;
			pckg = pckg + ckg >> 1;
			pckb = pckb + ckb >> 1;

			y1 = yp2[0+yrowlen] * KYF;
			y2 = yp2[1+yrowlen] * KYF;
			
			// use interpolation of chroma components here -> (ck + previous_ck) / 2
			b = y1 + pckb >> 8; rgbp2[0] = b;	if ( (u_long)b > 255 ) rgbp2[0] = ~(b >> 31);
			g = y1 + pckg >> 8; rgbp2[1] = g;	if ( (u_long)g > 255 ) rgbp2[1] = ~(g >> 31);
			r = y1 + pckr >> 8; rgbp2[2] = r;	if ( (u_long)r > 255 ) rgbp2[2] = ~(r >> 31);

			b = y2 + ckb >> 8; rgbp2[3] = b;	if ( (u_long)b > 255 ) rgbp2[3] = ~(b >> 31);
			g = y2 + ckg >> 8; rgbp2[4] = g;	if ( (u_long)g > 255 ) rgbp2[4] = ~(g >> 31);
			r = y2 + ckr >> 8; rgbp2[5] = r;	if ( (u_long)r > 255 ) rgbp2[5] = ~(r >> 31);

			y1 = yp2[0] * KYF;
			y2 = yp2[1] * KYF;

			rgbp2 += rgbpitch;
			// use interpolation of chroma components here -> (ck + previous_ck) / 2
			b = y1 + pckb >> 8; rgbp2[0] = b;	if ( (u_long)b > 255 ) rgbp2[0] = ~(b >> 31);
			g = y1 + pckg >> 8; rgbp2[1] = g;	if ( (u_long)g > 255 ) rgbp2[1] = ~(g >> 31);
			r = y1 + pckr >> 8; rgbp2[2] = r;	if ( (u_long)r > 255 ) rgbp2[2] = ~(r >> 31);

			b = y2 + ckb >> 8; rgbp2[3] = b;	if ( (u_long)b > 255 ) rgbp2[3] = ~(b >> 31);
			g = y2 + ckg >> 8; rgbp2[4] = g;	if ( (u_long)g > 255 ) rgbp2[4] = ~(g >> 31);
			r = y2 + ckr >> 8; rgbp2[5] = r;	if ( (u_long)r > 255 ) rgbp2[5] = ~(r >> 31);

			yp2 += 2;
			rgbp2 += 6 - rgbpitch;

			pckr = ckr;
			pckg = ckg;
			pckb = ckb;
		}
	}
}

//==================================================================
void yuv411_to_rgb( u_char *rgbp, const u_char *yp, const u_char *up, const u_char *vp, int w, int h, int uvrowlen )
{
int		i, j;
u_char	*rgbp2;
const u_char	*yp2;
const u_char	*up2, *vp2;
int		r, g, b;
int		y1, y2, ckr, ckg, ckb;
int		pckr, pckg, pckb;
int		yrowlen;
int		rgbpitch;

	rgbpitch = w * 3;
	yrowlen = w;
	for (i=h/2; i; --i)
	{
		rgbp2 = rgbp;
		rgbp += rgbpitch*2;

		yp2 = yp;	yp += yrowlen*2;
		up2 = up;	up += uvrowlen;
		vp2 = vp;	vp += uvrowlen;
		pckr = pckg = pckb = 0;
		for (j=w/2; j; --j)
		{
		int	u, v;

			u = (int)*up2++ - 128;
			v = (int)*vp2++ - 128;
			ckr =            v * KRVF;
			ckg = u * KGUF + v * KGVF;
			ckb = u * KBUF;

			pckr = pckr + ckr >> 1;
			pckg = pckg + ckg >> 1;
			pckb = pckb + ckb >> 1;

			y1 = yp2[0] * KYF;
			y2 = yp2[1] * KYF;

			// use interpolation of chroma components here -> (ck + previous_ck) / 2
			b = y1 + pckb >> 8; rgbp2[0] = b;	if ( (u_long)b > 255 ) rgbp2[0] = ~(b >> 31);
			g = y1 + pckg >> 8; rgbp2[1] = g;	if ( (u_long)g > 255 ) rgbp2[1] = ~(g >> 31);
			r = y1 + pckr >> 8; rgbp2[2] = r;	if ( (u_long)r > 255 ) rgbp2[2] = ~(r >> 31);

			b = y2 + ckb >> 8; rgbp2[3] = b;	if ( (u_long)b > 255 ) rgbp2[3] = ~(b >> 31);
			g = y2 + ckg >> 8; rgbp2[4] = g;	if ( (u_long)g > 255 ) rgbp2[4] = ~(g >> 31);
			r = y2 + ckr >> 8; rgbp2[5] = r;	if ( (u_long)r > 255 ) rgbp2[5] = ~(r >> 31);

			y1 = yp2[0+yrowlen] * KYF;
			y2 = yp2[1+yrowlen] * KYF;

			rgbp2 += rgbpitch;
			// use interpolation of chroma components here -> (ck + previous_ck) / 2
			b = y1 + pckb >> 8; rgbp2[0] = b;	if ( (u_long)b > 255 ) rgbp2[0] = ~(b >> 31);
			g = y1 + pckg >> 8; rgbp2[1] = g;	if ( (u_long)g > 255 ) rgbp2[1] = ~(g >> 31);
			r = y1 + pckr >> 8; rgbp2[2] = r;	if ( (u_long)r > 255 ) rgbp2[2] = ~(r >> 31);

			b = y2 + ckb >> 8; rgbp2[3] = b;	if ( (u_long)b > 255 ) rgbp2[3] = ~(b >> 31);
			g = y2 + ckg >> 8; rgbp2[4] = g;	if ( (u_long)g > 255 ) rgbp2[4] = ~(g >> 31);
			r = y2 + ckr >> 8; rgbp2[5] = r;	if ( (u_long)r > 255 ) rgbp2[5] = ~(r >> 31);

			yp2 += 2;
			rgbp2 += 6 - rgbpitch;

			pckr = ckr;
			pckg = ckg;
			pckb = ckb;
		}
	}
}

//==================================================================
void rgb_to_yuv411( u_char *yp, u_char *up, u_char *vp, const u_char *rgbp, int w, int h )
{
int				i, j;
int				r, g, b;
const u_char	*rgbp2;

	for (i=0; i < h; ++i)
	{
		rgbp2 = rgbp;
		rgbp += w * 3;
		for (j=w/2; j; --j)
		{
			r = rgbp2[0];
			g = rgbp2[1];
			b = rgbp2[2];	rgbp2 += 3;
			*yp++ = r * KYR + g * KYG + b * KYB +   0.0f;
			r = rgbp2[0];
			g = rgbp2[1];
			b = rgbp2[2];	rgbp2 += 3;
			*yp++ = r * KYR + g * KYG + b * KYB +   0.0f;

			if ( (i & 1) == 0 )
			{
				*up++ = r * KUR + g * KUG + b * KUB + 128.0f;
				*vp++ = r * KVR + g * KVG + b * KVB + 128.0f;
			}
		}
	}
}

//==================================================================
static inline float min3( float a, float b, float c )
{
	return (a < b ? (a < c ? a : c) : (b < c ? b : c));
}

//==================================================================
static inline float max3( float a, float b, float c )
{
	return (a > b ? (a > c ? a : c) : (b > c ? b : c));
}

//==================================================================
static __inline int rgb_to_hsi( int r, int g, int b, int &h, int &s, int &i )
{
	int		sum = r + g + b;
	
	float	o3osum = 255 * 3.0f / sum;

	i = (sum * (4096/3)) / 4096;

	s = 1 - o3osum / min3( r, g, b );

/*
	float var_Min = min3( var_R, var_G, var_B );    //Min. value of RGB

	l = ( var_Max + var_Min ) * 0.5f;

	if ( del_Max == 0 )						//This is a gray, no chroma...
	{
		h = 0;								//HSL results = 0 / 1
		s = 0;
	}
	else                                    //Chromatic data...
	{
		if ( l < 0.5f )	S = del_Max / ( var_Max + var_Min );
		else			S = del_Max / ( 2 - var_Max - var_Min );

		float del_R = ( ( ( var_Max - var_R ) * (1.0f/6) ) + ( del_Max * 0.5f ) ) / del_Max;
		float del_G = ( ( ( var_Max - var_G ) * (1.0f/6) ) + ( del_Max * 0.5f ) ) / del_Max;
		float del_B = ( ( ( var_Max - var_B ) * (1.0f/6) ) + ( del_Max * 0.5f ) ) / del_Max;

		if      ( var_R == var_Max ) H = del_B - del_G;
		else if ( var_G == var_Max ) H = ( 1 / 3 ) + del_R - del_B;
		else if ( var_B == var_Max ) H = ( 2 / 3 ) + del_G - del_R;

		if ( H < 0 ) ; H += 1;
		if ( H > 1 ) ; H -= 1;
	}
*/
	return 0;
}

//==================================================================
void rgb_to_hsl114( u_char *hp, u_char *sp, u_char *lp, const u_char *rgbp, int w, int h )
{
	/*
int				i, j;
int				r, g, b;
const u_char	*rgbp2;

	for (i=0; i < h; ++i)
	{
		rgbp2 = rgbp;
		rgbp += w * 3;
		for (j=w/2; j; --j)
		{
			int	r, g, b;

			r = rgbp2[0];
			g = rgbp2[1];
			b = rgbp2[2];	rgbp2 += 3;





			r = rgbp2[0];
			g = rgbp2[1];
			b = rgbp2[2];	rgbp2 += 3;
			*yp++ = r * KYR + g * KYG + b * KYB +   0.0f;
			r = rgbp2[0];
			g = rgbp2[1];
			b = rgbp2[2];	rgbp2 += 3;
			*yp++ = r * KYR + g * KYG + b * KYB +   0.0f;

			if ( (i & 1) == 0 )
			{
				*up++ = r * KUR + g * KUG + b * KUB + 128.0f;
				*vp++ = r * KVR + g * KVG + b * KVB + 128.0f;
			}
		}
	}
	*/
}